package com.cmii.sjw.department.control.jsc.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.Header;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cmii.sjw.department.control.common.RedisService;
import com.cmii.sjw.department.control.jsc.config.HxsConfig;
import com.cmii.sjw.department.control.jsc.config.SzqsConfig;
import com.cmii.sjw.department.control.jsc.config.XyzzConfig;
import com.cmii.sjw.department.control.jsc.exception.BaseException;
import com.cmii.sjw.department.control.jsc.mapper.UserMapper;
import com.cmii.sjw.department.control.jsc.model.User;
import com.cmii.sjw.department.control.jsc.service.AuthClientService;
import com.cmii.sjw.department.control.jsc.util.Result;
import com.cmii.sjw.department.control.jsc.util.Sm4Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Base64;

/**
 * @title 统一鉴权业务协同网关
 * @author jfh
 * @date 2024-11-12 周二 16:00
 * @version 1.0
 */
@Slf4j
@Service
public class AuthClientServiceImpl implements AuthClientService {

    @Autowired
    private SzqsConfig szqsConfig;

    @Autowired
    private HxsConfig hxsConfig;
    @Autowired
    private XyzzConfig xyzzConfig;

    @Autowired
    private RedisService redisService;

    @Autowired
    private UserMapper userMapper;


    /**
     * 数智强师鉴权网关
     * @param dcqcTk 数智强师token
     * @return 鉴权结果
     */
    @Override
    public Result<SaTokenInfo> authSzqs(String dcqcTk) {
        String cacheKey = "szqs:dcqc:accessToken:";
        String context = szqsConfig.getUrl();

        return auth(cacheKey,dcqcTk,context,szqsConfig.getAppKey(),szqsConfig.getAppSecret(),szqsConfig.getUserName());
    }

    /**
     * 惠学生鉴权网关
     * @param dcqcTk 惠学生token
     * @return 鉴权结果
     */
    @Override
    public Result<SaTokenInfo> authHxs(String dcqcTk) {
        String cacheKey = "hxs:dcqc:accessToken:";
        String context = hxsConfig.getUrl();

        return auth(cacheKey,dcqcTk,context,hxsConfig.getAppKey(),hxsConfig.getAppSecret(),hxsConfig.getUserName());
    }

    /**
     * 校园智治鉴权网关
     * @author jfh
     * @Date 2025/5/30 9:48
     * @param dcqcTk
     * @return com.cmii.sjw.department.control.jsc.util.Result<cn.dev33.satoken.stp.SaTokenInfo>
     */
    @Override
    public Result<SaTokenInfo> authXyzz(String dcqcTk) {
        String cacheKey = "xyzz:dcqc:accessToken:";
        String context = xyzzConfig.getUrl();

        return auth(cacheKey,dcqcTk,context,xyzzConfig.getAppKey(),xyzzConfig.getAppSecret(),xyzzConfig.getUserName());
    }


    /**
     * 鉴权网关
     * @param cacheKey 缓存key
     * @param dcqcTk dcqcTk
     * @param context 上下文
     * @param appKey appKey
     * @param appSecret appSecret
     * @param userName userName
     * @return 鉴权结果
     */
    private Result<SaTokenInfo> auth(String cacheKey ,String dcqcTk,String context, String appKey, String appSecret, String userName) {
        String apiToken = getApiToken(cacheKey,context,appKey, appSecret, userName);
        if (StringUtils.isEmpty(apiToken)) {
            return Result.error("获取API-TOKEN信息失败");
        }

        String accessToken = getAccessToken(apiToken,cacheKey,context,appKey, appSecret);
        if (StringUtils.isEmpty(accessToken)) {
            return Result.error("获取accessToken信息失败");
        }
        String accountId = getAccountId(dcqcTk,apiToken, accessToken,context,appKey,appSecret);
        if (StringUtils.isEmpty(accountId)) {
            return Result.error("获取accountId信息失败");
        }

        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getUserId, accountId)
                .eq(User::getStatus, "0")
                .in(User::getUserType, "01", "02"));

        if (ObjectUtil.isNull(user)) {
            return Result.error(401,"用户未注册驾驶舱");
        }
        if (user.getIsAuthorized().equals("0")) {
            return Result.error(402,"用户未授权");
        }

        StpUtil.login(user.getUserId());
        return Result.success("登录成功", StpUtil.getTokenInfo());
    }

    /**
     * 获取accountId
     * @param dcqcTk token
     * @param apiToken API-TOKEN
     * @param accessToken accessToken
     * @return accountId
     */
    private String getAccountId(String dcqcTk, String apiToken, String accessToken ,String context,String appKey,String appSecret) {
        try {
            URIBuilder uriBuilder = new URIBuilder(context+"/dcqc-apiserver/gateway/api/third-api/account-id");
            uriBuilder.addParameter("token", dcqcTk);
            uriBuilder.addParameter("accessToken", accessToken);
            String url = uriBuilder.build().toString();
            log.info("accountId接口信息 ,url:{},params:{}", url, uriBuilder);

            String apiResult = HttpUtil.createGet(url)
                    .header("API-TOKEN", apiToken)
                    .header("app-key", appKey)
                    .header("request-id", IdUtil.fastSimpleUUID())
                    .execute()
                    .body();
            log.info("accountId接口信息 url:{},apiResult:{}",url, apiResult);
            // 解析响应
            JSONObject response = JSON.parseObject(apiResult);
            validateResponse(response, "外层响应");

            JSONObject dataResponse = JSON.parseObject(response.getString("data"));
            validateResponse(dataResponse, "数据层响应");

            JSONObject accountData = JSON.parseObject(dataResponse.getString("data"));
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] encryptedData = decoder.decode(accountData.getString("accountId"));

            return new String(Sm4Utils.decrypt_Ecb_Padding(appSecret, encryptedData));
        } catch (Exception e) {
            log.error("获取accountId信息失败", e);
            throw new BaseException("获取accountId信息失败");
        }
    }

    /**
     * 验证响应
     * @param response 响应对象
     * @param layer 响应层级
     */
    private void validateResponse(JSONObject response, String layer) {
        if (!"200".equals(response.getString("code"))) {
            String errorMsg = String.format("%s验证响应错误, code:%s, message:%s",
                    layer, response.getString("code"), response.getString("msg"));
            log.error(errorMsg);
            throw new BaseException(errorMsg);
        }
    }

    /**
     * 获取accessToken
     * @param apiToken API-TOKEN
     * @return accessToken
     */
    private String getAccessToken(String apiToken,String cacheKey,String context, String appKey, String appSecret) {
        try {
            // 1. 尝试从缓存获取
//            cacheKey = cacheKey + apiToken+":";
//            String accessToken = redisService.getCache(cacheKey, String.class);
//            if (StringUtils.isNotEmpty(accessToken)) {
//                log.info("获取accessToken信息从缓存获取:{}", accessToken);
//                return accessToken;
//            }
            String accessToken = "";

            // 2. 缓存中没有，尝试从API获取
            URIBuilder uriBuilder = new URIBuilder(context+"/dcqc-apiserver/gateway/api/third-api/access-token");
            uriBuilder.addParameter("secret", appSecret);
            String url = uriBuilder.build().toString();

            String apiResult = HttpUtil.createGet(url)
                    .header("API-TOKEN", apiToken)
                    .header("app-key", appKey)
                    .header("request-id", IdUtil.fastSimpleUUID())
                    .execute()
                    .body();
            log.info("accessToken接口信息 url:{},apiResult:{}",url, apiResult);
            // 解析响应
            JSONObject response = JSON.parseObject(apiResult);
            validateResponse(response, "外层响应");

            JSONObject dataResponse = JSON.parseObject(response.getString("data"));
            validateResponse(dataResponse, "数据层响应");

            JSONObject tokenData = JSON.parseObject(dataResponse.getString("data"));
            accessToken = tokenData.getString("accessToken");
//            Long expiresIn = tokenData.getLong("expiresIn");

            // 3. 写入缓存
//            redisService.setCache(cacheKey, accessToken, expiresIn);
//            log.info("accessToken获取成功并缓存, token:{}, 过期时间:{}秒", accessToken, expiresIn);

            return accessToken;

        } catch (Exception e) {
            log.error("获取access-token信息失败", e);
            throw new BaseException("获取access-token信息失败");
        }
    }

    /**
     * 获取ApiToken
     * 获取apiToken
     * @return piToken
     */
    private String getApiToken(String cacheKey,String context,String appKey, String appSecret, String userName) {
        try {
            // 1. 尝试从缓存获取
            String token = "";
//            String token = redisService.getCache(cacheKey, String.class);
//            if (StringUtils.isNotEmpty(token)) {
//                log.info("获取API-TOKEN信息从缓存获取:{}", token);
//                return token;
//            }

            // 2. 缓存中没有，尝试从API获取
            JSONObject postData = new JSONObject()
                    .fluentPut("authKey", appKey)
                    .fluentPut("authSecret", appSecret)
                    .fluentPut("username", userName);
            log.info("postData:{}", postData.toJSONString());
            String url = context+"/dcqc-system/appKeySecret/apply/keyTokenByKey";
            String apiResult = HttpUtil.createPost(url)
                    .header(Header.CONTENT_TYPE, "application/json")
                    .body(postData.toJSONString())
                    .execute()
                    .body();
            log.info("API-TOKEN接口信息 url:{}, postData:{}, apiResult:{}",url, postData, apiResult);
            com.alibaba.fastjson2.JSONObject content = com.alibaba.fastjson2.JSON.parseObject(apiResult);
            if ("200".equals(content.getObject("code", String.class))) {
                log.info("获取API-TOKEN结果信息:{}", content.getString("data"));
                token = content.getObject("data", String.class);
                // 3. 写入缓存(设置10分钟过期)
//                redisService.setCache(cacheKey, token,  60 * 10);

                return token;
            } else {
                log.error("获取API-TOKEN错误信息 responseCode:{} responseMessage:{}", content.getString("code"), content.getString("msg"));
                throw new BaseException(content.getString("msg"));
            }
        } catch (Exception e) {
            log.error("获取API-TOKEN信息获取token失败", e);
            throw new BaseException("获取API-TOKEN信息获取token失败");
        }

    }


}
